home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Magnum One
/
Magnum One (Mid-American Digital) (Disc Manufacturing).iso
/
d12
/
v10n05.arc
/
2BOTH.ARC
/
2FLOPPY.ARC
/
2FLOPPY.C
< prev
next >
Wrap
Text File
|
1991-02-13
|
24KB
|
795 lines
/* PROJECT....: 2FLOPPY.C
** FILE.......: 2floppy.c
** VERSION....: 1.0 (Turbo C++ 1.0 & MSC 5.0)
** AUTHOR.....: Stephen D. Cooper
** NOTICE.....: Copyright 1990 ZIFF Communications Co.
**
** NOTES......: This file contains those routines that are unique to
** 2FLOPPY.EXE.
**
** COMPILE....: Turbo C ==> tcc -mc -O 2floppy.c fcommon.c
** MSC ==> cl /AC 2floppy.c fcommon.c
*/
/********************************************************************
** INCLUDE FILES **
********************************************************************/
#define MAIN_FILE
#include <conio.h>
#include <dos.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys\stat.h>
#include "2flo_err.h"
#include "compiler.h"
#include "fcommon.h"
/********************************************************************
** #define CONSTANTS **
********************************************************************/
#define FIELD_LIST_SIZE 72 /* Allows max (18 * 4)
format field list */
/********************************************************************
** GLOBAL VARIABLES **
********************************************************************/
char disk_field_list[FIELD_LIST_SIZE]; /* Format field list */
int beep_flag = TRUE; /* Beep? y/n */
int multiple_flag = FALSE; /* Multiple copies? */
int repetitions = 1; /* # of repetitions */
int verify_flag = TRUE; /* Verify copy? */
unsigned drivenumber; /* Target floppy drive */
unsigned sector_size_code; /* Format track sector size */
DISKSTATS dstats;
/********************************************************************
** FUNCTION DECLARATIONS **
********************************************************************/
int ask_permission(int flp_num);
int check_2file(void);
int check_reps(char *repnum);
int format_track(int track, int head, DISKSTATS *dstats);
int handle_flags(char *arg);
int process_file(void);
int process_args(int argc, char *argv[]);
int verify_buffs(int track, int head, char *buff1, char *buff2,
int buffsize);
int sector_write(union REGS *inregs, union REGS *outregs, char *buff,
DISKSTATS *dstats);
int write_sectors(int track, int head, DISKSTATS *dstats, char *buff);
void fanfare(void);
void help(void);
/********************************************************************
*********************************************************************
** CODE STARTS **
*********************************************************************
********************************************************************/
/********************************************************************
** FUNCTION....: main() **
********************************************************************/
void main(int argc, char *argv[])
{
int floppynum = 1;
int retval; /* Value returned by funcs */
/*
** Install our ctrl-break handler
** and our hardware error handler
*/
signal(SIGINT, ctrlbrk_handler);
HARDERR(harderr_handler);
fanfare(); /* Strut our stuff */
/*
** Process and error-check command line
*/
if((retval = process_args(argc, argv)) != 0)
err_exit(retval);
/*
** Check the file to make sure that it is a 2FILE file
*/
if((retval = check_2file()) != 0)
err_exit(retval);
/*
** Main processing
*/
while(repetitions-- > 0)
{
if((retval = ask_permission(floppynum++)) != 'Y')
err_exit(ERR_USER_ABORT);
if((retval = process_file()) != 0)
err_exit(retval);
}
/*
** Clean-up and go home
*/
fclose(fileptr);
free(read_buff);
printf("Program completed\n\n");
exit(ERR_NO_ERRORS);
}
/*********************************************************************
** FUNCTION....: ask_permission() **
** RETURNS.....: Either: 'Y' - User wants to proceed **
** 'N' - User wants to quit the program **
** NOTES.......: ask_permission() displays some useful statistics **
** about the file and the target disk, tells the user **
** that processing is about to commence, and asks the **
** user whether to continue or not. **
*********************************************************************/
int ask_permission(int flp_num)
{
int retval;
printf("\nSource file.............: %s\n", filename);
printf("Destination floppy drive: %c: ", drivenumber + 'A');
printf("(%u sides, %u tracks, %u sectors per track)\n",
dstats.sides, dstats.numtracks, dstats.numsectors);
printf("\nPlease insert floppy disk ");
if(multiple_flag)
printf("%d ", flp_num);
printf("into drive %c:\n", drivenumber + 'A');
printf("\nAbout to start copying. ");
if(beep_flag)
putchar(0x07);
retval = continue_yn();
printf("\n\n");
return(retval);
}
/*********************************************************************
** FUNCTION....: check_2file() **
** RETURNS.....: ERR_NO_ERRORS = Function successful **
** ERR_BAD_FILE_SIZE = The file is probably corrupt **
** ERR_BAD_HEADER = The file probably wasn't a **
** 2FILE file. **
** ERR_CANT_FIND_FILE = Couldn't get statistics **
** about the file (namely the **
** file's size). **
** ERR_CANT_OPEN_INPUT = fopen() could'nt open the **
** file. **
** ERR_READING_FILE = Problems reading file. **
** ERR_USER_ABORT = The user elected not to **
** continue after a critical **
** error. **
** NOTES.......: check_2file() checks out the file named on the **
** command line to make sure that it isn't corrupt or **
** a non-2FILE file. It also fills in our DISKSTATS **
** structure so that other parts of the program can **
** proceed. **
*********************************************************************/
int check_2file(void)
{
char inits[3]; /* File header initials */
int retval; /* Func return value */
unsigned long file_size; /* Size the file should be */
struct stat statbuff; /* To get file size */
/*
** Get file statistics (we need the size of the file)
*/
do
{
if((retval = stat(filename, &statbuff)) != 0)
return(ERR_CANT_FIND_FILE);
} while(harderr_status == HARDERR_RETRY);
if(harderr_status == HARDERR_ABORT)
err_exit(ERR_USER_ABORT);
/*
** Open the file
*/
do
{
if((fileptr = fopen(filename, "rb")) == NULL)
err_exit(ERR_CANT_OPEN_INPUT);
} while(harderr_status == HARDERR_RETRY);
if(harderr_status == HARDERR_ABORT)
err_exit(ERR_USER_ABORT);
prg_status = HARDERR_CRITICAL;
/*
** Check the header initials -- first 3 bytes
*/
retval = fread(inits, 3 * sizeof(char), 1, fileptr);
if(retval != 1)
return(ERR_READING_FILE);
if(inits[0] != INI_1 || inits[1] != INI_2 || inits[2] != INI_3)
return(ERR_BAD_HEADER);
/*
** Check file header disk stats
*/
retval = fread(&dstats, sizeof(dstats), 1, fileptr);
if(retval != 1)
return(ERR_READING_FILE);
if(dstats.drivenum != 0 && dstats.drivenum != 1)
return(ERR_BAD_HEADER);
if(dstats.sides != 1 && dstats.sides != 2)
return(ERR_BAD_HEADER);
if(dstats.numtracks != 40 && dstats.numtracks != 80)
return(ERR_BAD_HEADER);
/*
** We need to reset dstats.drivenum to the drivenumber
** that we got from the command line. (We did this in
** process_args so that check_filename() would work
** correctly. Then we overwrote the structure so that
** we could check the 2FILE file (in this function).
** Redundant? Maybe, but it works.)
*/
dstats.drivenum = drivenumber;
/*
** If we've made it this far, chances are VERY GOOD that we
** have a true-blue 2FILE file. If so, we've filled in our
** structure so that the rest of the program can continue.
** The only other check we need to make is the file's size.
** We check this to make sure that the copy we make will be
** good (if something happened while 2FILE was operating and
** the file is not the correct size, the resulting 2FLOPPY
** disk would be bad).
*/
/*
** Calculate the size the file should be
*/
file_size = (unsigned long)dstats.sectorsize;
file_size *= (unsigned long)dstats.numsectors;
file_size *= (unsigned long)dstats.numtracks;
file_size *= (unsigned long)dstats.sides;
file_size += (unsigned long)(sizeof(dstats) + 3);
/*
** Compare the actual size of the file and
** compare with what it should be. If it isn't
** the right size, tell the user the sizes involved.
*/
if(statbuff.st_size != file_size)
{
printf("Size (in bytes) the file should be....: ");
printf("%lu\n", file_size);
printf("Size (in bytes) the file actually is..: ");
printf("%lu\n", statbuff.st_size);
return(ERR_BAD_FILE_SIZE);
}
return(ERR_NO_ERRORS);
}
/*********************************************************************
** FUNCTION....: check_reps() **
** RETURNS.....: The int value of the string given on the command **
** line or -1 if atoi() returns less than 1. **
** NOTES.......: check_reps() converts a string to an integer and **
** checks the value for less than 1. **
*********************************************************************/
int check_reps(char *repnum)
{
int retval;
retval = atoi(repnum);
return(retval < 1 ? -1 : retval);
}
/*********************************************************************
** FUNCTION....: fanfare() **
** RETURNS.....: nothing **
** NOTES.......: fanfare() displays a copyright and author notice **
** notice. **
*********************************************************************/
void fanfare(void)
{
cputs("\r\n2FLOPPY version 1.0 Copyright 1990 ZIFF "
"Communications Co.\r\n");
cputs("PC Magazine ■ Stephen D. Cooper.\r\n\n");
}
/********************************************************************
** FUNCTION....: format_track() **
** **
** PARAMETERS..: int track = The track number to format **
** int head = The head (side) to format **
** DISKSTATS *dstats = A structure that contains **
** statistics about the disk **
** **
** RETURNS.....: ERR_NO_ERRORS = Function successful **
** ERR_FORMATTING_DISK = Problems formatting **
** ERR_HARD_DISK_FORMAT = The programmer asked the **
** function to format a track **
** on a hard disk (this **
** function only formats **
** floppy disks). **
** **
** NOTES.......: format_track() calls the bios to format a track **
** on a floppy disk. **
********************************************************************/
int format_track(int track, int head, DISKSTATS *dstats)
{
char *fieldlist = disk_field_list; /* Format field list */
int try_cntr = 3; /* If failure, try 3 times */
int retval;
int sector; /* Sector loop counter */
struct SREGS sregs;
union REGS inregs, outregs;
/*
** WE DON'T DO HARD DISKS!
*/
if(dstats->drivenum < 0 || dstats->drivenum > 1)
return(ERR_HARD_DISK_FORMAT);
for(sector = 1; sector <= dstats->numsectors; sector++)
{
*fieldlist++ = track;
*fieldlist++ = head;
*fieldlist++ = sector;
*fieldlist++ = sector_size_code;
}
inregs.h.ah = BIOSFUNC_FORMAT;
inregs.h.ch = track;
inregs.h.dh = head;
inregs.h.dl = dstats->drivenum;
inregs.x.bx = FP_OFF((char far *)disk_field_list);
do
{
sregs.es = FP_SEG((char far *)disk_field_list);
int86x(BIOS_DISK, &inregs, &outregs, &sregs);
if(outregs.h.ah)
if((retval = reset_drive(dstats->drivenum)) != 0)
return(retval);
} while(outregs.h.ah && --try_cntr > 0);
if(outregs.h.ah)
return(ERR_FORMATTING_DISK);
return(ERR_NO_ERRORS);
}
/*********************************************************************
** FUNCTION....: handle_flags() **
** **
** PARAMETERS..: char *arg = The command line argument to handle **
** **
** RETURNS.....: ERR_NO_ERRORS = function successful **
** ERR_BAD_REPETITIONS = The number of repetitions **
** given on the command line **
** was less than 1. **
** ERR_UNKNOWN_ARG = The argument on the command **
** line is invalid. **
** **
** NOTES.......: handle_flags() looks at the passed argument for **
** proper form and content and sets a global flag **
** accordingly. **
*********************************************************************/
int handle_flags(char *arg)
{
int retval = ERR_NO_ERRORS;
if(*arg == '/')
{
if(*(arg + 1) >= '0' && *(arg + 1) <= '9')
{
if((repetitions = check_reps(++arg)) == -1)
retval = ERR_BAD_REPETITIONS;
else
multiple_flag = TRUE;
}
else if(*(arg + 1) == 'Q' || *(arg + 1) == 'q')
beep_flag = FALSE;
else if(*(arg + 1) == 'V' || *(arg + 1) == 'v')
verify_flag = FALSE;
else
retval = ERR_UNKNOWN_ARG;
}
else
retval = ERR_UNKNOWN_ARG;
return(retval);
}
/*********************************************************************
** FUNCTION....: help() **
** **
** PARAMETERS..: none **
** **
** RETURNS.....: nothing **
** **
** NOTES.......: help() displays the program's command line help **
** screen. **
*********************************************************************/
void help(void)
{
char spc = ' ';
printf("Syntax: 2FLOPPY drive filename [/#] [/q] [/v]\n\n");
printf("Where: drive = The name of the destination floppy ");
printf("disk drive.\n\n");
printf("%8c filename = The name of the source file. The ", spc);
printf("current drive is the\n");
printf("%19c default drive. .FLP is the default ", spc);
printf("extension. The drive\n");
printf("%19c that contains filename must be different ", spc);
printf("from the\n");
printf("%19c destination floppy drive.\n\n", spc);
printf("%8c /#%7c= The number of floppy disk copies ", spc, spc);
printf("you wish to create.\n");
printf("%8c /q%7c= Quiet option (program won't beep ", spc, spc);
printf("when asking for a\n");
printf("%19c floppy disk).\n", spc);
printf("%8c /v%7c= No verify option (program won't ", spc, spc);
printf("verify the copy).\n\n");
printf("Note: The last three parameters (/#, /q, /v) are ");
printf("all optional and can be\n");
printf("%8c given in any order. The filename, /q, and /v ", spc);
printf("parameters can be\n");
printf("%8c either upper case or lower case.\n\n", spc);
}
/*********************************************************************
** FUNCTION....: process_args() **
** **
** PARAMETERS..: int argc = same as main() int argc **
** char *argv[] = same as main() char *argv[] **
** **
** RETURNS.....: ERR_NO_ERRORS = function successful **
** Any other value = An error was encountered. **
** **
** NOTES.......: process_args() processes all command line args **
*********************************************************************/
int process_args(int argc, char *argv[])
{
int retval; /* Value returned by funcs */
/*
** Check the number of DOS command line arguments
*/
if((retval = check_numargs(argc, 3, 6)) != 0)
{
help();
return(retval);
}
/*
** Check the first parameter --
** must be "A:" or "B:" (case insignificant)
*/
retval = floppyletter_2_number(&drivenumber, argv[1]);
if(retval != 0)
{
help();
return(retval);
}
/*
** Check the second parameter -- Must be a filename
** (default drive is current, default extension is .FLP)
*/
dstats.drivenum = drivenumber;
if((retval = check_filename(filename, argv[2], &dstats)) != 0)
{
help();
return(retval);
}
/*
** Check and process other command line arguments (/N /Q /V)
*/
while(--argc > 2)
if((retval = handle_flags(argv[argc])) != 0)
{
help();
return(retval);
}
return(ERR_NO_ERRORS);
}
/*********************************************************************
** FUNCTION....: process_file() **
** **
** PARAMETERS..: none **
** **
** RETURNS.....: ERR_NO_ERRORS = function successful **
** ERR_BAD_SECTORSIZE = The sector size in DISKSTATS **
** is one we're not set up for. **
** ERR_MEMORY = Can't malloc() enough memory **
** to complete processing. **
** **
** NOTES.......: process_file() is the main workhorse for the prg. **
** it calls on other functions to read, format **
** write, and verify and displays the progress of the **
** program to the user. **
*********************************************************************/
int process_file(void)
{
char *vbuff;
int retval;
int head, track;
int xhead, xtrack, yloc;
unsigned buffsize;
#if !defined(TURBO_C)
struct rccoord cursorpos;
#endif
switch(dstats.sectorsize)
{
case 128:
sector_size_code = 0;
break;
case 256:
sector_size_code = 1;
break;
case 512:
sector_size_code = 2;
break;
case 1024:
sector_size_code = 3;
break;
default:
fclose(fileptr);
return(ERR_BAD_SECTORSIZE);
}
/*
** Get our read buffer
*/
buffsize = dstats.sectorsize * dstats.numsectors;
buffsize *= sizeof(char);
if((read_buff = (char *)malloc(buffsize)) == 0) /* Main buff */
return(ERR_MEMORY);
if((vbuff = (char *)malloc(buffsize)) == 0) /* Verify buff */
return(ERR_MEMORY);
/*
** Rewind the file to the byte just past the file header
*/
fseek(fileptr, (long)(sizeof(dstats) + 3), SEEK_SET);
/*
** Read file, format floppy and write floppy
*/
printf("\n");
#if defined(TURBO_C)
xhead = wherex() + 18;
yloc = wherey();
#else
cursorpos = _gettextposition();
xhead = cusrorpos.col + 18;
yloc = cusrorpos.row;
#endif
xtrack = xhead + 9;
printf("Formatting: head 0, track 00");
for(track = 0; track < dstats.numtracks; track++)
{
GOTOXY(xtrack, yloc);
printf("%2u", track);
for(head = 0; head < dstats.sides; head++)
{
GOTOXY(xhead, yloc);
printf("%1u", head);
GOTOXY(1, yloc);
printf("Reading ");
retval = fread(read_buff, buffsize, 1, fileptr);
if(retval != 1)
{
retval = ERR_READING_FILE;
break;
}
GOTOXY(1, yloc);
printf("Formatting");
if((retval = format_track(track, head, &dstats)) != 0)
break;
GOTOXY(1, yloc);
printf("Writing ");
retval = write_sectors(track, head, &dstats, read_buff);
if(retval != 0)
break;
if(verify_flag)
{
GOTOXY(1, yloc);
printf("Verifying :");
retval = verify_buffs(track, head, read_buff, vbuff,
buffsize);
if(retval != 0)
break;
}
}
if(retval != ERR_NO_ERRORS)
break;
}
/*
** Clean up and return
*/
printf("\n");
free(vbuff);
free(read_buff);
return(retval);
}
/********************************************************************
** FUNCTION....: verify_buffs() **
** **
** PARAMETERS..: int track = The track number to verify **
** int head = The head number to verify **
** char *buff1 = The original memory buffer **
** char *buff2 = The verify buffer to read into **
** int buffsize = The size of the buffers **
** **
** RETURNS.....: ERR_NO_ERRORS = Good verify **
** ERR_BAD_VERIFY = Bad verify **
** **
** NOTES.......: verify_buffs() reads a track into a buffer and **
** compares that buffer with the buffer that was **
** used to write the track. **
********************************************************************/
int verify_buffs(int track, int head, char *buff1, char *buff2,
int buffsize)
{
int retval = ERR_NO_ERRORS;
if((retval = read_sectors(track, head, buff2, &dstats)) == 0)
if(memcmp(buff1, buff2, buffsize))
retval = ERR_BAD_VERIFY;
return(retval);
}
/********************************************************************
** FUNCTION....: write_sectors() **
** **
** PARAMETERS..: int track = The track to write **
** int head = The head to write **
** DISKSTATS *dstats = The disk statistics structure **
** char *buff = The buffer to write to disk **
** **
** RETURNS.....: ERR_NO_ERRORS = Track written successfully **
** Any other value = Problems writing track **
** **
** NOTES.......: write_sectors() uses the BIOS to write a buffer **
** to a track on a disk. **
********************************************************************/
int write_sectors(int track, int head, DISKSTATS *dstats, char *buff)
{
int retval;
unsigned char *newbuff;
union REGS inregs, outregs;
inregs.h.ah = BIOSFUNC_WRITE_SECTOR;
if(dstats->numsectors > 9)
inregs.h.al = 9;
else
inregs.h.al = dstats->numsectors;
inregs.h.ch = track;
inregs.h.cl = 1; /* Start with sector 1 */
inregs.h.dh = head;
inregs.h.dl = dstats->drivenum;
inregs.x.bx = FP_OFF((char far *)buff);
retval = sector_write(&inregs, &outregs, buff, dstats);
if(retval != 0)
return(retval);
if(dstats->numsectors > 9)
{
inregs.h.al = dstats->numsectors - 9;
inregs.h.cl = 10;
newbuff = buff + (9 * dstats->sectorsize);
inregs.x.bx = FP_OFF((char far *)newbuff);
retval = sector_write(&inregs, &outregs, newbuff, dstats);
}
return(retval);
}
/********************************************************************
** FUNCTION....: sector_write() **
** **
** PARAMETERS..: union REGS *inregs = int86x() union ALREADY **
** FILLED IN. **
** union REGS *outregs = int86x() union ALREADY **
** FILLED IN. **
** char *buff = The buffer to write to disk **
** DISKSTATS *dstats = Statistics about the disk **
** **
** RETURNS.....: ERR_NO_ERRORS = function successful **
** ERR_WRITING_SECTORS = Problems writing to track **
** **
** NOTES.......: sector_write() calls the BIOS to write char *buff **
** to a track on a disk. **
** **
** SPECIAL NOTE: This function exists because there **
** is a bug in the BIOS that crashes **
** whenever you try to write sectors **
** 9 and 10 to a track on a **
** high-density disk. With these **
** disks, write_sectors() calls this **
** routine twice (other disks only **
** once), once for sectors 1-9 and **
** the second time for sectors 10-? **
********************************************************************/
int sector_write(union REGS *inregs, union REGS *outregs, char *buff,
DISKSTATS *dstats)
{
int retval, try_cntr = 3;
struct SREGS sregs;
/*
** Try 3 times if not successful
*/
do
{
sregs.es = FP_SEG((char far *)buff);
int86x(BIOS_DISK, inregs, outregs, &sregs);
if(outregs->h.ah)
if((retval = reset_drive(dstats->drivenum)) != 0)
return(retval);
} while(outregs->h.ah && --try_cntr > 0);
return(outregs->h.ah == 0 ? 0 : ERR_WRITING_SECTORS);
}
/******************************
*******************************
**** END OF FILE 2floppy.c ****
*******************************
******************************/